home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / admin / xinetd.2 / xinetd / xinetd.2.1.7-linux.4 / libs / src / sio / siosup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-10  |  23.7 KB  |  1,118 lines

  1. /*
  2.  * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis
  3.  * All rights reserved.  The file named COPYRIGHT specifies the terms 
  4.  * and conditions for redistribution.
  5.  */
  6.  
  7. static char RCSid[] = "$Id: siosup.c,v 1.5 1995/09/10 18:35:09 chuck Exp $" ;
  8.  
  9. #include <sys/types.h>
  10. #include <sys/param.h>
  11. #include <sys/stat.h>
  12. #include <fcntl.h>
  13.  
  14. #include "impl.h"
  15. #include "sio.h"
  16.  
  17. #ifdef EVENTS
  18. #include "events.h"
  19. #endif
  20.  
  21. #if defined(BSD) || defined(linux)
  22. PRIVATE void terminate() ;
  23. PRIVATE status_e setup_read_buffer( register __sio_id_t *idp ,
  24.         unsigned buf_size );
  25. #endif
  26. char *malloc() ;
  27. char *realloc() ;
  28.  
  29.  
  30. static __sio_descriptor_t static_descriptor_array[ N_SIO_DESCRIPTORS ] ;
  31. static int n_descriptors = N_SIO_DESCRIPTORS ;
  32. __sio_descriptor_t *__sio_descriptors = static_descriptor_array ;
  33.  
  34. #ifdef EVENTS
  35. static events_s static___sio_events[ N_SIO_DESCRIPTORS ] ;
  36. events_s *__sio_events = static___sio_events ;
  37. #endif
  38.  
  39.  
  40. /*
  41.  * Code for finalization
  42.  */
  43. #ifdef HAS_FINALIZATION_FUNCTION
  44. static int finalizer_installed ;
  45.  
  46. SIO_DEFINE_FIN( sio_cleanup )
  47. {
  48.    (void) Sflush( SIO_FLUSH_ALL ) ;
  49. }
  50. #endif /* HAS_FINALIZATION_FUNCTION */
  51.  
  52.  
  53.  
  54. #ifdef HAS_MMAP
  55.  
  56. #define CHAR_NULL                ((char *)0)
  57.  
  58. /*
  59.  * PAGES_MAPPED gives the size of each map unit in pages
  60.  */
  61. #define PAGES_MAPPED                2
  62.  
  63. static size_t map_unit_size = 0 ;            /* bytes */
  64. static size_t page_size = 0 ;                    /* bytes */
  65.  
  66. static mapd_s static_mapd_array[ N_SIO_DESCRIPTORS ] ;
  67. static mapd_s *mmap_descriptors = static_mapd_array ;
  68.  
  69. #define MDP( fd )                ( mmap_descriptors + (fd) )
  70.  
  71.  
  72. /*
  73.  * NOTES ON MEMORY MAPPING:
  74.  *
  75.  *     1. Memory mapping works only for file descriptors opened for input
  76.  *        2. Mapping an object to a part of the address space where another
  77.  *            object is mapped will cause the old mapping to disappear (i.e. mmap
  78.  *            will not fail)
  79.  *
  80.  * Memory mapping interface:
  81.  *        SIO_MMAP : maps a file into a portion of the address space.
  82.  *        SIO_MUNMAP: unmap a portion of the address space
  83.  *        SIO_MNEED: indicate to the OS that we will need a portion of
  84.  *                         our address space.
  85.  *
  86.  * The map_unit_size variable defines how much of the file is mapped at
  87.  * a time. It is a multiple of the operating system page size. It is
  88.  * not less than SIO_BUFFER_SIZE unless SIO_BUFFER_SIZE is not a
  89.  * multiple of the page size (so the SIO_BUFFER_SIZE overrides
  90.  * PAGES_MAPPED).
  91.  *
  92.  * NOTE: All memory mapping code is in this file only
  93.  */
  94.  
  95.  
  96. /*
  97.  * Macros used by the memory mapping code
  98.  */
  99. #define FIRST_TIME( dp )                    ( dp->buf == NULL )
  100. #define FATAL_ERROR( msg )                    perror( msg ), exit( 1 )
  101.  
  102. /*
  103.  * Functions to support memory mapping:
  104.  *
  105.  *            try_memory_mapping
  106.  *            buffer_setup
  107.  *            __sio_switch
  108.  *            initial_map
  109.  *            map_unit
  110.  */
  111.  
  112. /*
  113.  * try_memory_mapping attempts to setup the specified descriptor
  114.  * for memory mapping. 
  115.  * It returns FAILURE if it fails and SUCCESS if it is successful.
  116.  * If HAS_MMAP is not defined, the function is defined to be FAILURE.
  117.  *
  118.  * Sets fields:
  119.  *        memory_mapped:             TRUE or FALSE
  120.  *        
  121.  * Also sets the following fields if memory_mapped is TRUE:
  122.  *    file_offset, file_size, buffer_size
  123.  *
  124.  */
  125. PRIVATE status_e try_memory_mapping( fd, idp, stp )
  126.     int fd ;
  127.     register __sio_id_t *idp ;
  128.     struct stat *stp ;
  129. {
  130.     int access ;
  131.  
  132. #ifdef EVENTS
  133.     EVENT( fd, EV_TRY_MEMORY_MAPPING ) ;
  134. #endif
  135.  
  136.     /*
  137.      * Do not try memory mapping if:
  138.      *        1) The file is not a regular file
  139.      *        2) The file is a regular file but has zero-length
  140.      *        3) The file pointer is not positioned at the beginning of the file
  141.      *        4) The fcntl to obtain the file descriptor flags fails
  142.      *        5) The access mode is not O_RDONLY or O_RDWR
  143.      *
  144.      * The operations are done in this order to avoid the system calls
  145.      * if possible.
  146.      */
  147.     if ( ( ( stp->st_mode & S_IFMT ) != S_IFREG ) ||
  148.           ( stp->st_size == 0 ) ||
  149.           ( lseek( fd, (long)0, 1 ) != 0 ) ||
  150.           ( ( access = fcntl( fd, F_GETFL, 0 ) ) == -1 ) ||
  151.           ( ( access &= 0x3 ) != O_RDONLY && access != O_RDWR ) )
  152.     {
  153.         idp->memory_mapped = FALSE ;
  154.         return( FAILURE ) ;
  155.     }
  156.  
  157.     /*
  158.      * Determine page_size and map_unit_size.
  159.      * Note that the code works even if PAGES_MAPPED is 0.
  160.      */
  161.     if ( page_size == 0 )
  162.     {
  163.         page_size = getpagesize() ;
  164.         map_unit_size = page_size * PAGES_MAPPED ;
  165.         if ( map_unit_size < SIO_BUFFER_SIZE )
  166.             if ( map_unit_size > 0 && SIO_BUFFER_SIZE % map_unit_size == 0 )
  167.                 map_unit_size = SIO_BUFFER_SIZE ;
  168.             else
  169.                 map_unit_size = page_size ;
  170.     }
  171.     
  172.     MDP(fd)->file_offset = 0 ;
  173.     MDP(fd)->file_size = stp->st_size ;
  174.     idp->buffer_size = map_unit_size ;
  175.     idp->buf = CHAR_NULL ;
  176.     idp->memory_mapped = TRUE ;
  177.  
  178.     return( SUCCESS ) ;
  179. }
  180.  
  181.  
  182. /*
  183.  * Copy the current_unit to the primary buffer
  184.  *
  185.  * Sets fields: start, end, nextb
  186.  * Also sets the file pointer
  187.  */
  188. PRIVATE void buffer_setup( idp, fd, mu_cur, mu_next )
  189.     __sio_id_t *idp ;
  190.     int fd ;
  191.     struct map_unit *mu_cur ;
  192.     struct map_unit *mu_next ;
  193. {
  194.     off_t new_offset ;
  195.  
  196.     sio_memcopy( mu_cur->addr, idp->buf, mu_cur->valid_bytes ) ;
  197.     idp->start = idp->buf ;
  198.     idp->end = idp->buf + mu_cur->valid_bytes ;
  199.     idp->nextb = idp->buf + ( idp->nextb - mu_cur->addr ) ;
  200.  
  201.     if ( mu_next->addr != CHAR_NULL )
  202.         new_offset = MDP(fd)->file_offset - mu_next->valid_bytes ;
  203.     else
  204.         new_offset = MDP(fd)->file_offset ;
  205.     (void) lseek( fd, new_offset, 0 ) ;
  206. }
  207.  
  208.  
  209. /*
  210.  * Switch from memory mapping to buffered I/O
  211.  * If any mapping has occured, then the current unit is
  212.  * copied into the buffer that is allocated.
  213.  * Any data in the next unit is ignored.
  214.  * We rely on idp->buf to identify the current unit (so it
  215.  * better be equal to the address of one of the units).
  216.  *
  217.  * Sets fields:
  218.  *            start, end, nextb
  219.  */
  220. status_e __sio_switch( idp, fd )
  221.     register __sio_id_t *idp ;
  222.     int fd ;
  223. {
  224.     register mapd_s *mdp = MDP( fd ) ;
  225.     struct map_unit *mu_cur, *mu_next ;
  226.     unsigned buffer_size = idp->buffer_size ;
  227.     char *buf_addr = idp->buf ;
  228.     int first_time = FIRST_TIME( idp ) ;
  229.     void buffer_setup() ;
  230.     status_e setup_read_buffer() ;
  231.  
  232. #ifdef EVENTS
  233.     EVENT( fd, EV_SIO_SWITCH ) ;
  234. #endif
  235.  
  236.     /*
  237.      * Initialize stream for buffering
  238.      */
  239.     if ( setup_read_buffer( idp, buffer_size ) == FAILURE )
  240.         return( FAILURE ) ;
  241.  
  242.     if ( ! first_time )
  243.     {
  244.         /*
  245.          * Find current, next unit
  246.          */
  247.         if ( buf_addr == mdp->first_unit.addr )
  248.         {
  249.             mu_cur = &mdp->first_unit ;
  250.             mu_next = &mdp->second_unit ;
  251.         }
  252.         else
  253.         {
  254.             mu_cur = &mdp->second_unit ;
  255.             mu_next = &mdp->first_unit ;
  256.         }
  257.  
  258.         buffer_setup( idp, fd, mu_cur, mu_next ) ;
  259.         /*
  260.          * Destroy all mappings
  261.          */
  262.         (void) SIO_MUNMAP( mu_cur->addr, mu_cur->mapped_bytes ) ;
  263.         if ( mu_next->addr != NULL )
  264.             (void) SIO_MUNMAP( mu_next->addr, mu_next->mapped_bytes ) ;
  265.     }
  266.     else
  267.         idp->start = idp->end = idp->nextb = idp->buf ;
  268.  
  269.     idp->memory_mapped = FALSE ;
  270.     return( SUCCESS ) ;
  271. }
  272.  
  273.  
  274. /*
  275.  * initial_map does the first memory map on the file descriptor.
  276.  * It attempts to map both units.
  277.  * The mapping always starts at file offset 0.
  278.  *
  279.  * SETS FIELDS:
  280.  *            first_unit.*, second_unit.*
  281.  *            file_offset
  282.  *
  283.  * Returns: 
  284.  *            number of bytes mapped in first_unit
  285.  *    or
  286.  *            0 to indicate that mmap failed.
  287.  */
  288. PRIVATE int initial_map( mdp, fd )
  289.     register mapd_s *mdp ;
  290.     int fd ;
  291. {
  292.     register caddr_t addr ;
  293.     register size_t requested_length = 2 * map_unit_size ;
  294.     register size_t mapped_length = MIN( mdp->file_size, requested_length ) ;
  295.     size_t bytes_left ;
  296.     register size_t bytes_in_unit ;
  297.  
  298. #ifdef EVENTS
  299.     EVENT( fd, EV_INITIAL_MAP ) ;
  300. #endif
  301.  
  302.     addr = SIO_MMAP( CHAR_NULL, mapped_length, fd, 0 ) ;
  303.     if ( (int) addr == -1 )
  304.         return( 0 ) ;
  305.  
  306.     SIO_MNEED( addr, mapped_length ) ;
  307.  
  308.     /*
  309.      * Map as much as possible in the first unit
  310.      */
  311.     bytes_in_unit = MIN( mapped_length, map_unit_size ) ;
  312.     mdp->first_unit.addr             = addr ;
  313.     mdp->first_unit.mapped_bytes     = bytes_in_unit ;
  314.     mdp->first_unit.valid_bytes     = bytes_in_unit ;
  315.  
  316.     /*
  317.      * If there is more, map it in the second unit.
  318.      */
  319.     bytes_left = mapped_length - bytes_in_unit ;
  320.     if ( bytes_left > 0 )
  321.     {
  322.         mdp->second_unit.addr             = addr + bytes_in_unit ;
  323.         mdp->second_unit.mapped_bytes = bytes_left ;
  324.         mdp->second_unit.valid_bytes     = bytes_left ;
  325.     }
  326.     else
  327.         mdp->second_unit.addr             = CHAR_NULL ;
  328.  
  329.     mdp->file_offset = mapped_length ;
  330.  
  331.     return( mdp->first_unit.valid_bytes ) ;
  332. }
  333.  
  334.  
  335. /*
  336.  * ALGORITHM:
  337.  *
  338.  *        if ( there are more bytes in the file )
  339.  *        {
  340.  *            map them at the given unit
  341.  *            update offset
  342.  *            issue SIO_MNEED()
  343.  *        }
  344.  *        else
  345.  *            unmap the unit
  346.  */
  347. PRIVATE status_e map_unit( mdp, fd, mup )
  348.     register mapd_s *mdp ;
  349.     int fd ;
  350.     register struct map_unit *mup ;
  351. {
  352.     register size_t bytes_left = mdp->file_size - mdp->file_offset ;
  353.     register size_t bytes_to_map = MIN( bytes_left, map_unit_size ) ;
  354.  
  355. #ifdef EVENTS
  356.     EVENT( fd, EV_MAP_UNIT ) ;
  357. #endif
  358.  
  359.     if ( bytes_to_map > 0 )
  360.     {
  361.         if ( (int) SIO_MMAP( mup->addr, bytes_to_map,
  362.                                                             fd, mdp->file_offset ) == -1 )
  363.             return( FAILURE ) ;            /* XXX: need to do more ? */
  364.         
  365.         mup->valid_bytes = bytes_to_map ;
  366.         ASSERT( mup->valid_bytes <= mup->mapped_bytes ) ;
  367.         mdp->file_offset += bytes_to_map ;
  368.         SIO_MNEED( mup->addr, mup->valid_bytes ) ;
  369.     }
  370.     else
  371.     {
  372.         (void) SIO_MUNMAP( mup->addr, mup->mapped_bytes ) ;
  373.         mup->addr = CHAR_NULL ;
  374.     }
  375.     return( SUCCESS ) ;
  376. }
  377.  
  378. #else
  379.  
  380. #define try_memory_mapping( x, y, z )                FAILURE
  381.  
  382. #endif /* HAS_MMAP */
  383.  
  384.  
  385. PRIVATE status_e setup_read_buffer( idp, buf_size )
  386.     register __sio_id_t *idp ;
  387.     unsigned buf_size ;
  388. {
  389.     register char *buf ;
  390.  
  391.     /*
  392.      * First allocate space for 2 buffers: primary and auxiliary
  393.      */
  394.     buf = malloc( buf_size * 2 ) ;
  395.     if ( buf == NULL )
  396.         return( FAILURE ) ;
  397.  
  398.     /*
  399.      * The descriptor buf field should point to the start of the main buffer
  400.      */
  401.     idp->buf = buf + buf_size ;
  402.     idp->buffer_size = buf_size ;
  403.     return( SUCCESS ) ;
  404. }
  405.  
  406.  
  407. PRIVATE status_e init_input_stream( idp, fd, stp )
  408.     register __sio_id_t *idp ;
  409.     int fd ;
  410.     struct stat *stp ;
  411. {
  412. #ifdef EVENTS
  413.     EVENT( fd, EV_INIT_INPUT_STREAM ) ;
  414. #endif
  415.  
  416.     /*
  417.      * First initialize the fields relevant to buffering: buf, buffer_size
  418.      */
  419.     if ( try_memory_mapping( fd, idp, stp ) == FAILURE )
  420.     {
  421.         /*
  422.          * Try to use normal buffering
  423.          */
  424.         unsigned buf_size = (unsigned)
  425.                             ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ;
  426.         
  427.         if ( setup_read_buffer( idp, buf_size ) == FAILURE )
  428.             return( FAILURE ) ;
  429.     }
  430.  
  431.      /*
  432.      * Initialize remaining descriptor fields
  433.      */
  434.     idp->max_line_length = 2 * idp->buffer_size - 1 ;
  435.     idp->start = idp->end = idp->nextb = idp->buf ;
  436.     idp->tied_fd = SIO_NO_TIED_FD ;
  437.  
  438.     return( SUCCESS ) ;
  439. }
  440.  
  441.  
  442. PRIVATE status_e init_output_stream( odp, fd, stp )
  443.     register __sio_od_t *odp ;
  444.     int fd ;
  445.     struct stat *stp ;
  446. {
  447.     register unsigned buf_size ;
  448.     register char *buf ;
  449.  
  450. #ifdef EVENTS
  451.     EVENT( fd, EV_INIT_OUTPUT_STREAM ) ;
  452. #endif
  453.  
  454.     buf_size = (unsigned)
  455.                         ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ;
  456.     buf = malloc( buf_size ) ;
  457.     if ( buf == NULL )
  458.         return( FAILURE ) ;
  459.     
  460.     /*
  461.      * Initialize buffering fields
  462.      */
  463.     odp->buf = buf ;
  464.     odp->buffer_size = buf_size ;
  465.     odp->buf_end = odp->buf + buf_size ;
  466.  
  467.     /*
  468.      * Initialize remaining fields
  469.      */
  470.     odp->start = odp->nextb = odp->buf ;
  471.     if ( isatty( fd ) )
  472.         odp->buftype = SIO_LINEBUF ;
  473.  
  474.     if ( fd == 2 )
  475.         odp->buftype = SIO_NOBUF ;
  476.  
  477.     return( SUCCESS ) ;
  478. }
  479.  
  480.  
  481. #ifndef HAS_ISATTY
  482.  
  483. #ifdef HAS_SYSVTTY
  484.  
  485. #include <termio.h>
  486.  
  487. PRIVATE int isatty( fd )
  488.     int fd ;
  489. {
  490.     struct termio t ;
  491.  
  492.     if ( ioctl( fd, TCGETA, &t ) == -1 && errno == ENOTTY )
  493.         return( FALSE ) ;
  494.     else
  495.         return( TRUE ) ;
  496. }
  497. #endif    /* HAS_SYSVTTY */
  498.  
  499. #ifdef HAS_BSDTTY
  500.  
  501. #include <sgtty.h>
  502.  
  503. PRIVATE int isatty( fd )
  504.     int fd ;
  505. {
  506.     struct sgttyb s ;
  507.  
  508.     if ( ioctl( fd, TIOCGETP, &s ) == -1 && errno == ENOTTY )
  509.         return( FALSE ) ;
  510.     else
  511.         return( TRUE ) ;
  512. }
  513. #endif    /* HAS_BSDTTY */
  514.  
  515. #endif    /* ! HAS_ISATTY */
  516.  
  517.  
  518. /*
  519.  * Initialize stream I/O for a file descriptor.
  520.  *
  521.  * Arguments:
  522.  *        fd:                file descriptor
  523.  *        dp:                descriptor pointer
  524.  *        stream_type:     either __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM
  525.  *
  526.  * Returns
  527.  *        0             if successful
  528.  *      SIO_ERR    if the file descriptor is not valid (sets errno)
  529.  *   exits        if stream_type is not __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM
  530.  */
  531. int __sio_init( dp, fd, stream_type )
  532.     register __sio_descriptor_t *dp ;
  533.     int fd ;
  534.     enum __sio_stream stream_type ;
  535. {
  536.     struct stat st ;
  537. #if !defined(linux) && !defined(BSD)
  538.     void terminate() ;
  539. #endif
  540.  
  541. #ifdef EVENTS
  542.     EVENT( fd, EV_SIO_INIT ) ;
  543. #endif
  544.  
  545.     if ( fstat( fd, &st ) == -1 )
  546.         return( SIO_ERR ) ;
  547.  
  548.     switch ( stream_type )
  549.     {
  550.         case __SIO_INPUT_STREAM:
  551.             if ( init_input_stream( IDP( dp ), fd, &st ) == FAILURE )
  552.                 return( SIO_ERR ) ;
  553.             break ;
  554.  
  555.         case __SIO_OUTPUT_STREAM:
  556.             if ( init_output_stream( ODP( dp ), fd, &st ) == FAILURE )
  557.                 return( SIO_ERR ) ;
  558.             break ;
  559.             
  560.         default:
  561.             terminate( "SIO __sio_init: bad stream type (internal error).\n" ) ;
  562.             /* NOTREACHED */
  563.     }
  564.     dp->stream_type = stream_type ;
  565.     dp->initialized = TRUE ;
  566.  
  567. #ifdef HAS_FINALIZATION_FUNCTION
  568.     if ( ! finalizer_installed )
  569.     {
  570.         if ( ! SIO_FINALIZE( sio_cleanup ) )
  571.         {
  572.             char *s = "SIO __sio_init: finalizer installation failed\n" ;
  573.  
  574.             (void) write( 2, s, strlen( s ) ) ;
  575.         }
  576.         else
  577.             finalizer_installed = TRUE ;
  578.     }
  579. #endif /* HAS_FINALIZATION_FUNCTION */
  580.  
  581.     return( 0 ) ;
  582. }
  583.  
  584.  
  585. /*
  586.  * __sio_writef writes the data in the buffer to the file descriptor.
  587.  *
  588.  * It tries to write as much data as possible until either all data
  589.  * are written or an error occurs. EINTR is the only error that is
  590.  * ignored.
  591.  * In case an error occurs but some data were written, that number
  592.  * is returned instead of SIO_ERR.
  593.  *
  594.  * Fields modified:
  595.  *        When successful: start, nextb
  596.  *        When not successful: start
  597.  *
  598.  * Return value:
  599.  *        Number of bytes written
  600.  *        SIO_ERR, if write(2) fails and no data were written
  601.  */ 
  602. int __sio_writef( odp, fd )
  603.     register __sio_od_t *odp ;
  604.     int fd ;
  605. {
  606.     register int b_in_buffer ;
  607.     register int cc_total = 0 ;
  608.  
  609. #ifdef EVENTS
  610.     EVENT( fd, EV_SIO_WRITEF ) ;
  611. #endif
  612.  
  613.     /*
  614.      * Make sure we don't exceed the buffer limits
  615.      *    Maybe we should log this ?            XXX
  616.      */
  617.     if ( odp->nextb > odp->buf_end )
  618.         odp->nextb = odp->buf_end ;
  619.  
  620.     b_in_buffer = odp->nextb - odp->start ;
  621.  
  622.     if ( b_in_buffer == 0 )
  623.         return( 0 ) ;
  624.     
  625.     for ( ;; )
  626.     {
  627.         register int cc ;
  628.  
  629.         cc = write( fd, odp->start, b_in_buffer ) ;
  630.         if ( cc == b_in_buffer )
  631.         {
  632.             odp->start = odp->nextb = odp->buf ;
  633.             cc_total += cc ;
  634.             break ;
  635.         }
  636.         else if ( cc == -1 )
  637.         {
  638.             if ( errno == EINTR )
  639.                 continue ;
  640.             else
  641.                 /*
  642.                  * If some bytes were written, return that number, otherwise
  643.                  * return SIO_ERR
  644.                  */
  645.                 return( ( cc_total != 0 ) ? cc_total : SIO_ERR ) ;
  646.         }
  647.         else            /* some bytes were written */
  648.         {
  649.             odp->start += cc ;            /* advance start of buffer */
  650.             b_in_buffer -= cc ;            /* decrease number bytes left in buffer */
  651.             cc_total += cc ;                /* count the bytes that were written */
  652.         }
  653.     }
  654.     return( cc_total ) ;
  655. }
  656.  
  657.  
  658. /*
  659.  * __sio_readf reads data from the file descriptor into the buffer.
  660.  * Unlike __sio_writef it does NOT try to read as much data as will fit
  661.  * in the buffer. It ignores EINTR.
  662.  *
  663.  * Returns: # of bytes read or SIO_ERR
  664.  *
  665.  * Fields set:
  666.  *         If it does not return SIO_ERR, it sets start, nextb, end
  667.  *            If it returns SIO_ERR, it does not change anything
  668.  */
  669. int __sio_readf( idp, fd )
  670.     register __sio_id_t *idp ;
  671.     int fd ;
  672. {
  673.     register int cc ;
  674.  
  675. #ifdef EVENTS
  676.     EVENT( fd, EV_SIO_READF ) ;
  677. #endif
  678.  
  679.     /*
  680.      * First check for a tied fd and flush the stream if necessary
  681.      *
  682.      *         XXX    the return value of __sio_writef is not checked.
  683.      *                    Is that right ?
  684.      */
  685.     if ( idp->tied_fd != SIO_NO_TIED_FD )
  686.         (void) __sio_writef( &__SIO_OD( idp->tied_fd ), idp->tied_fd ) ;
  687.  
  688. #ifdef HAS_MMAP
  689.     if ( idp->memory_mapped )
  690.     {
  691.         register mapd_s *mdp = MDP( fd ) ;
  692.  
  693.         /*
  694.          * The functions initial_map and map_unit may fail.
  695.          * In either case, we switch to buffered I/O.
  696.          * If initial_map fails, we have read no data, so we
  697.          * should perform a read(2).
  698.          * If map_unit fails (for the next unit), we still have
  699.          * the data in the current unit, so we can return.
  700.          */
  701.         if ( FIRST_TIME( idp ) )
  702.         {
  703.             cc = initial_map( mdp, fd ) ;
  704.             if ( cc > 0 )
  705.                 idp->buf = mdp->first_unit.addr ;
  706.             else
  707.             {
  708.                 if ( __sio_switch( idp, fd ) == FAILURE )
  709.                     return( SIO_ERR ) ;
  710.                 cc = -1 ;
  711.             }
  712.         }
  713.         else
  714.         {
  715.             register struct map_unit *mu_cur, *mu_next ;
  716.  
  717.             if ( idp->buf == mdp->first_unit.addr )
  718.             {
  719.                 mu_cur = &mdp->first_unit ;
  720.                 mu_next = &mdp->second_unit ;
  721.             }
  722.             else
  723.             {
  724.                 mu_cur = &mdp->second_unit ;
  725.                 mu_next = &mdp->first_unit ;
  726.             }
  727.  
  728.             if ( mu_next->addr != NULL )
  729.             {
  730.                 idp->buf = mu_next->addr ;
  731.                 cc = mu_next->valid_bytes ;
  732.                 /*
  733.                  * XXX:  Here we may return SIO_ERR even though there
  734.                  *           are data in the current unit because the switch
  735.                  *           fails (possibly because malloc failed).
  736.                  */
  737.                 if ( map_unit( mdp, fd, mu_cur ) == FAILURE &&
  738.                                         __sio_switch( idp, fd ) == FAILURE )
  739.                     return( SIO_ERR ) ;
  740.             }
  741.             else
  742.                 cc = 0 ;
  743.         }
  744.         if ( cc >= 0 )
  745.         {
  746.             idp->end = idp->buf + cc ;
  747.             idp->start = idp->nextb = idp->buf ;
  748.             return( cc ) ;
  749.         }
  750.     }
  751. #endif /* HAS_MMAP */
  752.  
  753.     for ( ;; )
  754.     {
  755.         cc = read( fd, idp->buf, (int) idp->buffer_size ) ;
  756.         if ( cc == -1 )
  757.             if ( errno == EINTR )
  758.                 continue ;
  759.             else
  760.                 return( SIO_ERR ) ;
  761.         else
  762.             break ;
  763.     }
  764.  
  765.     idp->end = idp->buf + cc ;
  766.     idp->start = idp->nextb = idp->buf ;
  767.     return( cc ) ;
  768. }
  769.  
  770.  
  771. /*
  772.  * __sio_extend_buffer is used by Srdline to extend the buffer
  773.  * If successful, it returns the number of bytes that have been read.
  774.  * If it fails (because of end-of-file or I/O error), it returns 0 or -1.
  775.  *
  776.  * Fields modified:
  777.  *     idp->start points to the start of the buffer area (which is in the
  778.  *     auxiliary buffer)
  779.  *        Also, if successful, idp->nextb is set to idp->buf, idp->end is modified.
  780.  */
  781. int __sio_extend_buffer( idp, fd, b_left )
  782.     register __sio_id_t *idp ;
  783.     int fd ;
  784.     register int b_left ;
  785. {
  786.     register int b_read ;
  787.  
  788. #ifdef EVENTS
  789.     EVENT( fd, EV_SIO_EXTEND_BUFFER ) ;
  790. #endif
  791.  
  792.     /*
  793.      * copy to auxiliary buffer
  794.      */
  795.     if ( b_left )
  796.         sio_memcopy( idp->nextb, idp->buf - b_left, b_left ) ;
  797.     b_read = __sio_readf( idp, fd ) ;
  798.     idp->start = idp->buf - b_left ;
  799.     return( b_read ) ;
  800. }
  801.  
  802.  
  803. /*
  804.  * __sio_more tries to read more data from the given file descriptor iff
  805.  * there is free space in the buffer.
  806.  * __sio_more is used only by Srdline and only AFTER __sio_extend_buffer
  807.  * has been called. This implies that 
  808.  *        a) this is not a memory mapped file
  809.  *        b) __sio_readf has been called (so we don't need to check for tied fd's
  810.  *
  811.  * Fields modified (only if successful):
  812.  *            idp->end
  813.  *
  814.  * Return value: the number of bytes read.
  815.  */
  816. int __sio_more( idp, fd )
  817.     register __sio_id_t *idp ;
  818.     int fd ;
  819. {
  820.     register int b_left = &idp->buf[ idp->buffer_size ] - idp->end ;
  821.     register int cc ;
  822.  
  823. #ifdef EVENTS
  824.     EVENT( fd, EV_SIO_MORE ) ;
  825. #endif
  826.  
  827.     if ( b_left <= 0 )
  828.         return( 0 ) ;
  829.     
  830.     for ( ;; )
  831.     {
  832.         cc = read( fd, idp->end, b_left ) ;
  833.         if ( cc >= 0 )
  834.         {
  835.             idp->end += cc ;
  836.             return( cc ) ;
  837.         }
  838.         else
  839.             if ( errno == EINTR )
  840.                 continue ;
  841.             else
  842.                 return( SIO_ERR ) ;
  843.     }
  844. }
  845.  
  846.  
  847. /*
  848.  * Finalize a buffer by unmapping the file or freeing the malloc'ed memory
  849.  */
  850. int Sdone( fd )
  851.     int fd ;
  852. {
  853.     register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
  854.  
  855. #ifdef EVENTS
  856.     EVENT( fd, EV_SDONE ) ;
  857. #endif
  858.  
  859.     if ( ! DESCRIPTOR_INITIALIZED( dp ) )
  860.     {
  861.         errno = EBADF ;
  862.         return( SIO_ERR ) ;
  863.     }
  864.  
  865.     switch ( dp->stream_type )
  866.     {
  867.         case __SIO_INPUT_STREAM:
  868.             {
  869.                 register __sio_id_t *idp = IDP( dp ) ;
  870.  
  871. #ifdef HAS_MMAP
  872.                 if ( idp->memory_mapped )
  873.                 {
  874.                     register mapd_s *mdp = MDP( fd ) ;
  875.  
  876.                     if ( mdp->first_unit.addr != CHAR_NULL )
  877.                         (void) SIO_MUNMAP( mdp->first_unit.addr,
  878.                                                         mdp->first_unit.mapped_bytes ) ;
  879.                     if ( mdp->second_unit.addr != CHAR_NULL )
  880.                         (void) SIO_MUNMAP( mdp->second_unit.addr,
  881.                                                         mdp->second_unit.mapped_bytes ) ;
  882.                     idp->memory_mapped = FALSE ;
  883.                 }
  884.                 else
  885. #endif    /* HAS_MMAP */
  886.                     free( idp->buf - idp->buffer_size ) ;
  887.                     idp->nextb = idp->end = NULL ;
  888.             }
  889.             break ;
  890.         
  891.         case __SIO_OUTPUT_STREAM:
  892.             {
  893.                 register __sio_od_t *odp = ODP( dp ) ;
  894.  
  895.                 if ( Sflush( fd ) == SIO_ERR )
  896.                     return( SIO_ERR ) ;
  897.                 free( odp->buf ) ;
  898.                 odp->nextb = odp->buf_end = NULL ;
  899.             }
  900.             break ;
  901.         
  902.         default:
  903.             terminate( "SIO Sdone: bad stream type\n" ) ;
  904.     }
  905.  
  906.     dp->initialized = FALSE ;
  907.     return( 0 ) ;
  908. }
  909.  
  910.  
  911. PRIVATE char *expand( area, old_size, new_size, is_static )
  912.     char *area ;
  913.     unsigned old_size, new_size ;
  914.     int is_static ;
  915. {
  916.     char *new_area ;
  917.  
  918.     if ( is_static )
  919.     {
  920.         if ( ( new_area = malloc( new_size ) ) == NULL )
  921.             return( NULL ) ;
  922.         sio_memcopy( area, new_area, old_size ) ;
  923.     }
  924.     else
  925.         if ( ( new_area = realloc( area, new_size ) ) == NULL )
  926.             return( NULL ) ;
  927.     return( new_area ) ;
  928. }
  929.  
  930.  
  931. #include <sys/time.h>
  932. #include <sys/resource.h>
  933.  
  934. PRIVATE int get_fd_limit()
  935. {
  936. #ifdef RLIMIT_NOFILE
  937.  
  938.     struct rlimit rl ;
  939.  
  940.     (void) getrlimit( RLIMIT_NOFILE, &rl ) ;
  941.     return( rl.rlim_cur ) ;
  942.  
  943. #else
  944.  
  945.     return( N_SIO_DESCRIPTORS ) ;
  946.  
  947. #endif
  948. }
  949.  
  950. /*
  951.  * Expand the descriptor array (and if we use memory mapping the
  952.  * memory mapping descriptors). We first expand the memory mapping
  953.  * descriptors.
  954.  * There is no problem if the expansion of the SIO descriptors fails
  955.  * (i.e. there is no need to undo anything).
  956.  */
  957. int Smorefds()
  958. {
  959.     char *p ;
  960.     int is_static ;
  961.     unsigned new_size, old_size ;
  962.     int n_fds = get_fd_limit() ;
  963.  
  964.     if ( n_fds <= n_descriptors )
  965.         return( 0 ) ;
  966.  
  967. #ifdef EVENTS
  968.     old_size = n_descriptors * sizeof( events_s ) ;
  969.     new_size = n_fds * sizeof( events_s ) ;
  970.     is_static = ( __sio_events == static___sio_events ) ;
  971.     p = expand( (char *)__sio_events, old_size, new_size, is_static ) ;
  972.     if ( p == NULL )
  973.         return( SIO_ERR ) ;
  974.     __sio_events = (events_s *) p ;
  975.  
  976.     /*
  977.      * Clear the codes field of the extra events structs.
  978.      * We have to do this because a non-null codes field implies that
  979.      * events recording is on for that fd
  980.      */
  981.     {
  982.         int i ;
  983.  
  984.         for ( i = n_descriptors ; i < n_fds ; i++ )
  985.             __sio_events[i].codes = NULL ;
  986.     }
  987. #endif    /* EVENTS */
  988.  
  989. #ifdef HAS_MMAP
  990.     old_size = n_descriptors * sizeof( mapd_s ) ;
  991.     new_size = n_fds * sizeof( mapd_s ) ;
  992.     is_static = ( mmap_descriptors == static_mapd_array ) ;
  993.     p = expand( (char *)mmap_descriptors, old_size, new_size, is_static ) ;
  994.     if ( p == NULL )
  995.         return( SIO_ERR ) ;
  996.     mmap_descriptors = (mapd_s *) p ;
  997. #endif    /* HAS_MMAP */
  998.     
  999.     old_size = n_descriptors * sizeof( __sio_descriptor_t ) ;
  1000.     new_size = n_fds * sizeof( __sio_descriptor_t ) ;
  1001.     is_static =  ( __sio_descriptors == static_descriptor_array ) ;
  1002.     p = expand( (char *)__sio_descriptors, old_size, new_size, is_static ) ;
  1003.     if ( p == NULL )
  1004.         return( SIO_ERR ) ;
  1005.     __sio_descriptors = (__sio_descriptor_t *) p ;
  1006.  
  1007.     n_descriptors = n_fds ;
  1008.     return( 0 ) ;
  1009. }
  1010.  
  1011.  
  1012. #ifdef EVENTS
  1013.  
  1014. /*
  1015.  * Enable recording of events for the specified file descriptor
  1016.  */
  1017. int __sio_enable_events( fd )
  1018.     int fd ;
  1019. {
  1020.     char *p = malloc( EVENT_ENTRIES * sizeof( short ) ) ;
  1021.  
  1022.     if ( p == NULL )
  1023.         return( SIO_ERR ) ;
  1024.  
  1025.     __sio_events[ fd ].codes = (short *) p ;
  1026.     return( 0 ) ;
  1027. }
  1028.  
  1029.  
  1030. /*
  1031.  * Disable recording of events for the specified file descriptor
  1032.  */
  1033. void __sio_disable_events( fd )
  1034.     int fd ;
  1035. {
  1036.     if ( __sio_events[ fd ].codes != NULL )
  1037.     {
  1038.         free( (char *) __sio_events[ fd ].codes ) ;
  1039.         __sio_events[ fd ].codes = NULL ;
  1040.     }
  1041. }
  1042.  
  1043.  
  1044. /*
  1045.  * Move stored events to buf
  1046.  */
  1047. int __sio_get_events( fd, buf, size )
  1048.     int fd ;
  1049.     char *buf ;
  1050.     int size ;
  1051. {
  1052.     events_s *evp = &__sio_events[ fd ] ;
  1053.     int bufentries ;
  1054.     int range1, range2 ;
  1055.     int diff ;
  1056.     char *p ;
  1057.     int cc ;
  1058.     int cc_total ;
  1059.     int move_entries ;
  1060.  
  1061.     if ( evp->codes == NULL )
  1062.         return( 0 ) ;
  1063.     
  1064.     diff = evp->next - evp->start ;
  1065.     if ( diff == 0 )
  1066.         return( 0 ) ;
  1067.  
  1068.     if ( diff > 0 )
  1069.     {
  1070.         range1 = diff ;
  1071.         range2 = 0 ;
  1072.     }
  1073.     else
  1074.     {
  1075.         range1 = EVENT_ENTRIES - evp->start ;
  1076.         range2 = evp->next ;
  1077.     }
  1078.  
  1079.     bufentries = size / sizeof( short ) ;
  1080.     p = buf ;
  1081.     cc_total = 0 ;
  1082.  
  1083.     move_entries = MIN( range1, bufentries ) ;
  1084.     cc = move_entries * sizeof( short ) ;
  1085.     sio_memcopy( (char *) &evp->codes[ evp->start ], p, cc ) ;
  1086.     cc_total += cc ;
  1087.     p += cc ;
  1088.     bufentries -= range1 ;
  1089.     ADD( evp->start, move_entries ) ;
  1090.  
  1091.     if ( bufentries == 0 || range2 == 0 )
  1092.         return( cc_total ) ;
  1093.  
  1094.     move_entries = MIN( range2, bufentries ) ;
  1095.     cc = move_entries * sizeof( short ) ;
  1096.     sio_memcopy(  (char *) &evp->codes[ evp->start ], p, cc ) ;
  1097.     cc_total += cc ;
  1098.     ADD( evp->start, move_entries ) ;
  1099.  
  1100.     return( cc_total ) ;
  1101. }
  1102.  
  1103. #endif     /* EVENTS */
  1104.  
  1105.  
  1106. /*
  1107.  * Simple function that prints the string s at stderr and then calls
  1108.  * exit
  1109.  */
  1110. PRIVATE void terminate( s )
  1111.     char *s ;
  1112. {
  1113.     (void) write( 2, s, strlen( s ) ) ;
  1114.     (void) abort() ;
  1115.     exit( 1 ) ;                /* in case abort fails */
  1116. }
  1117.  
  1118.